/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfast.framework.orm;

import com.jfast.framework.exception.DataSourceException;
import com.jfast.framework.log.Logger;
import com.jfast.framework.orm.annotation.Transaction;
import com.jfast.framework.orm.config.DataSourceManager;
import com.jfast.framework.orm.config.DbConfig;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * 事物拦截器
 * @author zengjintao
 * @version 1.0
 * @createTime 2018年1月15日下午8:28:37
 */
public class TxInterceptor implements MethodInterceptor {
	
	private static final Logger logger = Logger.getLogger(TxInterceptor.class);

	private DbConfig getDbConfig(Transaction transaction) {
		if (transaction != null) {
			DbConfig dbConfig = DataSourceManager.getDbConfig(transaction.configName());
			if (dbConfig == null)
				throw new RuntimeException("DbConfig not found with Transaction: " + transaction.configName());
			return dbConfig;
		}
		return null;
	}
	
	private int getTransactionLevel(Transaction transaction){
		return transaction.transactionIsolation();
	}
	
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Transaction transaction = invocation.getMethod().getAnnotation(Transaction.class);
		DbConfig dbConfig = getDbConfig(transaction);
		
		Connection conn = dbConfig.getThreadLocalConnection();
		if (conn != null) {	// Nested transaction support
			try {
				if (conn.getTransactionIsolation() < getTransactionLevel(transaction))
				     conn.setTransactionIsolation(getTransactionLevel(transaction));
				invocation.proceed();
			} catch (SQLException e) {
				throw new DataSourceException(e);
			}
		}
		Boolean autoCommit = null;
		try {
			conn = dbConfig.getConnection();
			autoCommit = conn.getAutoCommit();
			dbConfig.setThreadLocalConnection(conn);
			conn.setTransactionIsolation(getTransactionLevel(transaction));
			conn.setAutoCommit(false);
			invocation.proceed();
			conn.commit();
		} catch (Throwable t) {
			if (conn != null) try {conn.rollback();} catch (Exception e) {}
			logger.error("数据操作异常",t);
		} finally {
			if (conn != null) {
				if (autoCommit != null)
					conn.setAutoCommit(autoCommit);
				conn.close();
			}
			dbConfig.removeThreadLocalConnection();
		}
		return null;
	}
}
